<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */
namespace app\service\cdc\cost;

use app\enum\FsCodeEnum;
use app\enum\CostServiceCostEnum;
use app\model\CostTaskAccountModel;
use app\model\CostTaskMediaNoticeLogModel;
use app\model\TaskMediaNoticeModel;
use app\service\BaseService;
use app\service\client\AccountService;
use app\service\notice\NoticeInterface;
use app\service\notice\NoticeService;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;

final class TaskNoticeService extends BaseService
{
    /**
     * 发送提醒消息.
     * @param CostTaskMediaNoticeLogModel $model 媒体通知模型
     */
    public static function sendNoticeMsg(CostTaskMediaNoticeLogModel $model): bool
    {
        if (! $model->getKey()) {
            return self::setError('消息信息不存在');
        }
        if ($model->getAttr('status') == CostServiceCostEnum::NOTICE_STATUS_SUCCESS) {
            return true;
        }
        $service = NoticeService::getInstance($model->getAttr('type'));
        if (! $service instanceof NoticeInterface) {
            return self::setError('实例化消息服务错误');
        }
        // 更新数据库状态
        try {
            $res = $service->sendStaffMsg(json_decode($model->getAttr('staff_id'), true), $model->getAttr('msg'));
            $model->setAttr('send_time', date('Y-m-d H:i:s'));
            $model->setAttr('status', CostServiceCostEnum::TASK_STATUS_SUCCESS);
            if ($res['code'] != FsCodeEnum::SUCCESS) {
                $model->setAttr('status', CostServiceCostEnum::TASK_STATUS_FAIL);
                $model->setAttr('error_msg', json_encode($res));
            }
            $model->save();
            return true;
        } catch (\Exception $e) {
            return self::setError('修改task_media_notice_log表失败：' . $e->getMessage());
        }
    }

    /**
     * 新增task_media_notice_log表数据.
     * @param int $code 错误返回码
     * @param array $params 返回结构体
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function insertNoticeLogData(int $code = 0, array $params = []): bool
    {
        // 验证字段
        if (! $code) {
            return self::setError('错误码不能为空');
        }
        $noticeData = self::getNoticeModel($code, $params['media_id'] ?? 0);
        if (! $noticeData->getKey()) {
            return self::setError('错误码不存在');
        }
        $data = $params;
        $msg = self::getMsg($noticeData->getAttr('msg'), $data['advertiser_id'], $data['msg']);
        $data['code'] = $code;
        $data['msg'] = $msg;
        $data['staff_id'] = $noticeData->getAttr('staff_id');
        $data['type'] = $noticeData->getAttr('type');
        try {
            // 判断是否存在未发送的同款数据，如果有，不入库
            if (self::getNoticeLog($params['account_id'], $data['type'], $params['task_account_id'], $code, $msg)) {
                return true;
            }
            $model = new CostTaskMediaNoticeLogModel();
            $model->setAttrs($data);
            $model->save();
            return true;
        } catch (\Exception $e) {
            return self::setError('插入task_media_notice_log表失败：' . $e->getMessage());
        }
    }

    /**
     * 系统错误提醒.
     * @param int $accountId 账户id
     * @param string $msg 错误信息
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function systemErrorNotice(int $code = 0, int $accountId = 0, string $msg = '', int $taskAccountId = 0): bool
    {
        $clientAccountModel = AccountService::getAccountModel($accountId);
        if (! $clientAccountModel->getKey()) {
            return self::setError('client_account数据不存在');
        }
        $data = [
            'media_id' => $clientAccountModel->getAttr('media_id'),
            'account_id' => $clientAccountModel->getAttr('id'),
            'advertiser_id' => $clientAccountModel->getAttr('advertiser_id'),
            'msg' => $msg,
            'task_account_id' => $taskAccountId,
        ];
        return self::insertNoticeLogData($code, $data);
    }

    /**
     * 接口错误提醒.
     * @param CostTaskAccountModel $model task模型
     * @param PullService $pullService 拉数据服务
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function mediaErrorNotice(CostTaskAccountModel $model, PullService $pullService): bool
    {
        // 获取通知类型
        $code = self::getMsgCode($pullService->getResponseCode(), $model->getAttr('media_id'));
        if (! $code) {
            return false;
        }
        $data = [
            'media_id' => $model->getAttr('media_id'),
            'account_id' => $model->getAttr('account_id'),
            'advertiser_id' => $model->getAttr('advertiser_id'),
            'msg' => $pullService->getResponseMsg(),
            'task_account_id' => $model->getKey(),
        ];
        return self::insertNoticeLogData($code, $data);
    }

    /**
     * 获取task_media_notice_log表模型.
     * @param int $id 主键id
     * @return null|array|CostTaskMediaNoticeLogModel|mixed|Model
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function getTaskNoticeModel(int $id = 0)
    {
        return (new CostTaskMediaNoticeLogModel())->find($id);
    }

    /**
     * 获取task_media_notice列表.
     * @return array|Collection
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function getNoticeLogList()
    {
        $where = [
            ['status', '=', CostServiceCostEnum::TASK_STATUS_WAIT],
        ];
        return (new CostTaskMediaNoticeLogModel())->where($where)->order('id asc')->select();
    }

    /**
     * 获取task_media_notice.
     * @param int $accountId 账户id
     * @param int $type 类型
     * @param int $taskAccountId 任务表id
     * @param int $code 错误码
     * @param string $msg 错误信息
     * @return null|array|CostTaskMediaNoticeLogModel|mixed|Model
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function getNoticeLog(int $accountId = 0, int $type = 0, int $taskAccountId = 0, int $code = 0, string $msg = '')
    {
        $where = [
            ['account_id', '=', $accountId],
            ['task_account_id', '=', $taskAccountId],
            ['type', '=', $type],
            ['status', '=', CostServiceCostEnum::TASK_STATUS_WAIT],
            ['code', '=', $code],
            ['msg', '=', $msg],
        ];
        return (new CostTaskMediaNoticeLogModel())->where($where)->find();
    }

    /**
     * 解析媒体错误消息.
     * @param mixed $code 错误返回码
     * @param int $mediaId 媒体id
     * @return bool|int
     */
    private static function getMsgCode($code, int $mediaId = 0)
    {
        if (empty($code)) {
            return self::setError('返回错误码为空');
        }
        if (! isset(CostServiceCostEnum::MEDIA_ERROR_AUTH_CODE[$mediaId])) {
            return self::setError('媒体消息类型不存在');
        }
        // 获取通知类型
        return self::getCode(strval($code), $mediaId);
    }

    /**
     * 获取提醒信息.
     * @param string $body 消息结构体
     * @param string $advertiserId 账户id
     * @param string $msg 消息内容
     * @return array|string|string[]
     */
    private static function getMsg(string $body = '', string $advertiserId = '', string $msg = '')
    {
        return str_replace(['{advertiser_id}', '{msg}'], [$advertiserId, $msg], $body);
    }

    /**
     * 获取task_media_notice.
     * @param int $code 错误码
     * @param int $mediaId 媒体id
     * @return null|array|mixed|Model|TaskMediaNoticeModel
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private static function getNoticeModel(int $code = 0, int $mediaId = 0)
    {
        $where = [
            ['code', '=', $code],
            ['media_id', '=', $mediaId],
        ];
        return (new TaskMediaNoticeModel())->where($where)->find();
    }

    /**
     * 获取错误码.
     * @param string $code 返回码
     * @param int $mediaId 媒体id
     */
    private static function getCode(string $code = '', int $mediaId = 0): int
    {
        $codeArr = CostServiceCostEnum::MEDIA_ERROR_AUTH_CODE[$mediaId];
        if (in_array($code, $codeArr)) {
            return CostServiceCostEnum::ERROR_AUTH_CODE;
        }
        return CostServiceCostEnum::ERROR_API_CODE;
    }
}
